
/*   RolGPS Project
 * 
 *   Copyright (C) 2009 Pablo Alejandro Costesich <rhfixer@gmail.com>
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */
package org.rolgps.libnlink.connection;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.rolgps.libnlink.database.Simple;
import org.rolgps.libnlink.protocol.CommEventHandler;
import org.rolgps.libnstack.exception.DatabaseException;
import org.rolgps.libnstack.message.GenericMessage;
import org.rolgps.libnstack.protocol.KVDB;
import org.rolgps.libnstack.protocol.Message;

/**
 *
 * @author xeph
 */
public class Messenger{

    private Socket connection = null;
    private int socketPort = 4321;
    private String hostname = "localhost";
    private String name = null;
    private String[] myServices = new String[0];
    ThreadGroup serviceThreads = new ThreadGroup("MessengerServices " + Thread.currentThread().getName());
    SocketListener socketListener = new SocketListener();
    SocketSender socketSender = new SocketSender();
    Thread socketListenerThread = new Thread(serviceThreads, socketListener, "SocketListenerThread");
    Thread socketSenderThread = new Thread(serviceThreads, socketSender, "SocketSenderThread");

    /**
     *
     * @param name
     * @param services
     */
    public Messenger(String name, String[] services) {
        this.name = name;
        this.myServices = services;
        sendHandshake();
        run();
    }

    /**
     *
     * @param name
     * @param hostname
     * @param services
     */
    public Messenger(String name, String hostname, String[] services) {

        this.name = name;
        this.hostname = hostname;
        this.myServices = services;

        sendHandshake();
        run();
    }

    /**
     *
     * @param name
     * @param hostname
     * @param port
     * @param services
     */
    public Messenger(String name, String hostname, int port, String[] services) {

        this.name = name;
        this.hostname = hostname;
        this.socketPort = port;
        this.myServices = services;

        sendHandshake();
        run();
    }

    /**
     *
     * @return
     */
    public String getName() {
        return name;
    }

    /**
     *
     */
    public void shutdown() {
        socketListener.shutdown();
        socketSender.shutdown();
        serviceThreads.destroy();
    }

    /**
     *
     */
    private void sendHandshake() {
        Message handshake = new GenericMessage();
        handshake.sendTo("main");
        handshake.addHeader("type", "handshake");
        handshake.addTuple("service", this.getName());
        for (String service : myServices) {
            handshake.addTuple("service", service);
        }
        this.sendMessage(handshake);
//        System.err.println("HANDSHAKE sent");
    }

    /**
     *
     * @param message
     */

//    int iter=0;
    public void sendMessage(Message message) {
//        System.err.println("Adding message to queue");
        socketSender.sendMessage(message);
//        System.err.println("Done. No.: "+iter);
//        iter++;
    }

    /**
     *
     * @param handler
     */
    public void addListener(CommEventHandler handler) {
//        System.err.println("Adding listener");
        socketListener.addObserver(new CommEvent(handler));
//        System.out.println("Observers: "+socketListener.countObservers());
    }

    /**
     *
     * @param usr
     * @param passwd
     * @return
     * @throws org.rolgps.libnstack.exception.DatabaseException
     */
    public KVDB openDB(String usr, String passwd) throws DatabaseException {
        Simple result = new Simple(usr, passwd);
        socketListener.addObserver(result);
        return result;
    }

    /**
     *
     */
    public void run() {
        try {
            connection = new Socket(getHostname(), getPort());
            assert connection != null;

            socketListener.setSocket(connection);
            socketSender.setSocket(connection, getName());

            socketListenerThread.start();
            socketSenderThread.start();
//

//            socketListenerThread.setDaemon(true);
//            socketSenderThread.setDaemon(true);
            
//            socketListenerThread.join();
//            socketSenderThread.join();
        } catch (UnknownHostException ex) {
            Logger.getLogger(Messenger.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Messenger.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     *
     * @return
     */
    public int getPort() {
        return socketPort;
    }

    /**
     *
     * @param socketPort
     */
    public void setPort(int socketPort) {
        this.socketPort = socketPort;
    }

    /**
     *
     * @return
     */
    public String getHostname() {
        return hostname;
    }

    /**
     * 
     * @param hostname
     */
    public void setHostname(String hostname) {
        this.hostname = hostname;
    }
}
